package com.wuhuahe.luanfeng.netty.example.privateprotocol;

import io.netty.buffer.ByteBuf;
import org.jboss.marshalling.ByteInput;

import java.io.IOException;
import java.io.InputStream;

/**
 * Created By wuhuahe
 * author:游龙
 * Date: 2018-07-14
 * Time: 10:39
 * Desc:
 */
public class ChannelBufferByteInput implements ByteInput {
    private final ByteBuf buf;
    public ChannelBufferByteInput(ByteBuf buf) {
        this.buf = buf;
    }

    /**
     * Reads the next byte of data from the input stream.  If no byte is available because the end of the stream has
     * been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream
     * is detected, or an exception is thrown.
     *
     * @return the next byte, or -1 if the end of stream has been reached
     * @throws IOException if an error occurs
     */
    @Override
    public int read() throws IOException {
        if(buf.isReadable()){
            return buf.readByte() & 0xff;
        }
        return -1;
    }

    /**
     * Read some bytes from the input stream into the given array.  Returns the number of bytes actually read (possibly
     * zero), or -1 if the end of stream has been reached.
     *
     * @param b the destination array
     * @return the number of bytes read (possibly zero), or -1 if the end of stream has been reached
     * @throws IOException if an error occurs
     */
    @Override
    public int read(byte[] b) throws IOException {
        return read(b, 0, b.length);
    }

    /**
     * Read some bytes from the input stream into the given array.  Returns the number of bytes actually read (possibly
     * zero), or -1 if the end of stream has been reached.
     *
     * @param b   the destination array
     * @param off the offset into the array into which data should be read
     * @param len the number of bytes to attempt to fill in the destination array
     * @return the number of bytes read (possibly zero), or -1 if the end of stream has been reached
     * @throws IOException if an error occurs
     */
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int available = available();
        if(available == 0){
            return -1;
        }
        len = Math.min(available, len);
        buf.readBytes(b, off, len);
        return len;
    }

    /**
     * Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without
     * blocking by the next invocation of a method for this input stream.
     *
     * @return the number of bytes
     * @throws IOException if an error occurs
     */
    @Override
    public int available() throws IOException {
        return buf.readableBytes();
    }

    /**
     * Skips over and discards up to {@code n} bytes of data from this input stream.  If the end of stream is reached,
     * this method returns {@code 0} in order to be consistent with {@link InputStream#skip(long)}.
     *
     * @param n the number of bytes to attempt to skip
     * @return the number of bytes skipped
     * @throws IOException if an error occurs
     */
    @Override
    public long skip(long n) throws IOException {
        int readable = buf.readableBytes();
        if(readable < n){
            n = readable;
        }
        buf.readerIndex((int) (buf.readerIndex() + n));
        return n;
    }

    /**
     * Closes this stream and releases any system resources associated
     * with it. If the stream is already closed then invoking this
     * method has no effect.
     * <p>
     * <p> As noted in {@link AutoCloseable#close()}, cases where the
     * close may fail require careful attention. It is strongly advised
     * to relinquish the underlying resources and to internally
     * <em>mark</em> the {@code Closeable} as closed, prior to throwing
     * the {@code IOException}.
     *
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void close() throws IOException {

    }
}
